﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Configuration;
using System.Threading;
using System.Threading.Tasks;
using NLog;

namespace Gollie.Administration.Service
{
	public enum Frequency
	{
		Hourly = 1,
		Daily = 2,
		Weekly = 3,
		Monthly = 4,
		Yearly = 5
	}
	
	public class AdministrationTask
	{
		private static readonly Logger logger = LogManager.GetCurrentClassLogger();

		CancellationTokenSource cts;
		internal DateTime LastProcessTime = new DateTime(1980, 1, 1, 1, 1, 1);

		public AdministrationTask(TaskConfigElement taskConfig, CancellationTokenSource cts)
		{
			this.cts = cts;

			this.ReadConfig(taskConfig);
		}

		public bool Process(DateTime now)
		{
			bool mustExecute = false;

			switch (this.Frequency)
			{
				case Frequency.Hourly:
					mustExecute = this.HandleHourly(now);
					break;
				case Frequency.Daily:
					mustExecute = this.HandleDaily(now);
					break;
				case Frequency.Weekly:
					mustExecute = this.HandleWeekly(now);
					break;
				case Frequency.Monthly:
					mustExecute = this.HandleMonthly(now);
					break;
				case Frequency.Yearly:
					mustExecute = this.HandleYearly(now);
					break;
			}

			return mustExecute;
		}

		private bool HandleYearly(DateTime now)
		{
			if (now.Minute != this.OnMinute)
				return false;

			if (now.Hour != this.OnHour)
				return false;

			if (now.Day != this.OnDay)
				return false;

			if (now.Month != this.OnMonth)
				return false;

			if (now.Date == LastProcessTime.Date)
				return false;

			return true;
		}

		private bool HandleMonthly(DateTime now)
		{
			if (now.Minute != this.OnMinute)
				return false;

			if (now.Hour != this.OnHour)
				return false;

			if (now.Day != this.OnDay)
				return false;

			if (now.Date == LastProcessTime.Date)
				return false;

			return true;
		}

		private bool HandleWeekly(DateTime now)
		{
			if (now.Minute != this.OnMinute)
				return false;

			if (now.Hour != this.OnHour)
				return false;

			if (now.DayOfWeek != this.DayOfWeek)
				return false;

			if (now.Date == LastProcessTime.Date)
				return false;

			return true;
		}

		private bool HandleDaily(DateTime now)
		{
			if (now.Minute != this.OnMinute)
				return false;

			if (now.Hour != this.OnHour)
				return false;

			if (now.Date == LastProcessTime.Date)
				return false;

			return true;
		}

		private bool HandleHourly(DateTime now)
		{
			if (now.Minute != this.OnMinute)
				return false;

			if (now.Hour == LastProcessTime.Hour)
				return false;

			return true;
		}

		private void ReadConfig(TaskConfigElement taskConfig)
		{
			switch (taskConfig.Frequency)
			{
				case "hour": this.Frequency = Frequency.Hourly;
					break;
				case "day": this.Frequency = Frequency.Daily;
					break;
				case "week": this.Frequency = Frequency.Weekly;
					break;
				case "month": this.Frequency = Frequency.Monthly;
					break;
				case "year": this.Frequency = Frequency.Yearly;
					break;
				default: throw new ConfigurationErrorsException("Unknown frequency " + taskConfig.Frequency + ". Check config file.");
			}

			this.Name = taskConfig.Name;
			this.Type = Type.GetType(taskConfig.Task);
			this.OnDay = taskConfig.OnDay;
			this.OnHour = taskConfig.OnHour;
			this.OnMinute = taskConfig.OnMinute;
			this.DayOfWeek = (DayOfWeek)taskConfig.OnWeekDay;
			this.OnMonth = taskConfig.OnMonth;
			this.ShortDescription = taskConfig.ShortDesc;
		}

		public string Name { get; private set; }

		public Type Type { get; private set; }

		public Frequency Frequency {get; private set; }

		public int OnHour { get; private set; }

		public int OnMinute { get; private set; }

		public int OnDay { get; private set; }

		public DayOfWeek DayOfWeek { get; private set; }

		public int OnMonth { get; private set; }

		public string ShortDescription { get; private set; }
	}
}
